(二)nRF52 Blinky FreeRTOS 例程分析

除非注明,本站博客均为原创或翻译,转载请务必注明出处并保留原文链接:文章来源于喵兄研发日记


[TOC]


工程简介

​ 与上一个例程不同之处在于,本工程中添加有FreeRTOS,犹记得当年用nRF51822时,对第三方的RTOS支持还不是太好。

代码分析

​ 直接上图,main函数中的代码如下,主要分三段:设备时钟初始化、LED引脚设置以及创建任务及定时器,最后启动任务调度。

QQ截图20170220161409

​ 引脚相关配置、控制逻辑这里不再详述,参考(一)即可,先看设备时钟部分,再看RTOS。

nRF设备时钟模块

QQ截图20170220161807

​ 设备始终初始化操作中基本上在对m_clock_cb结构体进行初始化操作,主要有:清除事件的头指针,请求计数置0。其次是使能了高频时钟中断及设置低频时钟的时钟源。先瞅瞅该结构体是啥玩意:

QQ截图20170220162356

​ 可以看到该结构体模块用来保存初始化状态、高低频时钟开启状态以及高低频时钟的请求计数值;除此之外,每个时钟还有一个事件指针,以链表形式挂载着一系列的待处理事件。事件块的结构如下图所示, 在当前的事件块中,保存着下一个事件的结构体指针以及当前事件的回调处理函数。

QQ截图20170220162930

​ 看完介绍好像一头雾水,再看看时钟模块提供的其它API接口(高低频时钟接口类型一样):

QQ截图20170220164017

​ 时钟模块对外提供的3个主要函数,先介绍request函数,当有事件需要处理时,调用request函数将会:1. 时钟未启动,将事件添加到队列中,启动时钟,事件将在时钟中断程序中异步执行;2. 时钟已启动,在request函数中直接执行此事件函数。

​ release函数则在每次调用后减少一次请求数,当请求数为0时,停止时钟,is_running函数则是查询时钟运行状态。

​ 暂时没看懂这样做有什么用 = =

FreeRTOS简单分析

​ 既然本例程使用了FreeRTOS,当然得介绍一下,不过此处不做RTOS内部分析,只简单介绍它是怎么跑起来的。先从nRF52的启动文件arm_startup_nrf52.s开始,同STM32一样,在程序正常启动进入main函数之前,先触发硬件复位中断进入了SystemInit函数中。

QQ截图20170220171238

​ 简单看了一下系统初始化过程,主要是初始化了系统外设时钟,没看出来跟FreeRTOS有啥牵连。再进入到main函数中瞅瞅,函数内总共调用FreeRTOS做了三件事:创建一个进程、创建并启动一个定时器、启动任务调度器。因此FreeRTOS与硬件时钟相关的交互部分肯定在这其中了。干脆直奔vTaskStartScheduler()函数,该函数主要调用了xPortStartScheduler()函数,这使得vTaskStartScheduler函数在应用层具备通用性,而xPortStartScheduler则具备可移植性,nice!

QQ截图20170220172057

​ 再看看xPortStartScheduler函数中主要做的事情,设置PendSV中断优先级,启动RTC中断作为FreeRTOS的systick中断,最后启动第一个任务。

​ 看到这里还是蒙B,PendSV及RTC中断跟FreeRTOS有舍联系?搜一下其中断回调函数可发现玄机:工程中FreeRTOS的SVC系统调用及PendSV可悬挂调用直接宏定义成了对应的硬件中断回调函数!当这两个中断触发时,便会去调用FreeRTOS的系统调用函数去实现任务调度。

QQ截图20170220172619

​ 那SVC/PendSV中断怎样才会触发呢?别忘了,还有一个RTC中断函数,FreeRTOS的xPortSysTickHandler函数被宏定义成了RTC1的硬件中断回调函数,RTC1定时器启动后就会定期的触发中断用作精准的RTOS滴答计数以及触发相关的服务中断,接下来看看定时器中断xPortSysTickHandler中的执行内容:

QQ截图20170220173450

​ 定时器就做了两件事:计数值+1以及触发PendSV中断,使用PendSV的好处是保证其它硬件中断的实时性不会被定时器打断而强制性切换到线程中,否则会触发硬件错误。当没有其它硬件中断时,MCU执行PendSV以切换RTOS的上下文。对于SysTick、SVC、以及PendSV三者之间是如何具体的实现任务的上下文切换,将在以后的RTOS篇中详述。

Liu Lu wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!

热评文章